#ifndef LILY_BASIC
#define LILY_BASIC

#ifdef __cplusplus
extern "C"
{
#endif

#define isUpper(c) ('A' <= c && c <= 'Z')
#define isLower(c) ('a' <= c && c <= 'z')
#define toUpper(c) (c & ~0x20)
#define toLower(c) (c | 0x20)
#define reLU(c) (c ^ 0x20)

#define isA(c) (isLower(c) || isUpper(c))
#define isD(c) ('0' <= c && c <= '9')

	char str_startwith(const char *s, const char *cmd);
	int32_t str_contains(const char *s, char c);
	int32_t str_contains_by_str(const char *s, char *c);
	char str_equal(const char *s, const char *cmd);
	int32_t str_index(const char *s, char c);
	int32_t str_index_right(char *s, char c);
	char str_lower(char *str);
	char str_replace(char *s, char from, char to);
	char str_replace_by_str(char *s, const char *from, char to);
	char *strReplace(const char *src, const char *from, const char *to);
	int32_t str_is_numeric(const char *name);
	int32_t str_is_name(const char *name);
	int32_t str_count_n(const char *str1, const char *str2);
	char int_to_string(int32_t n, char *s);

	float str_to_float(char *s);

	void str_insert_at(char *s, char c, int32_t at);

	float *get_nums_from_rx(char *rs, int32_t *length_back);
	char **get_paras_from_rx(char *rx, int32_t *len);

	void limit_to(float *x, float max);
	void limit_from_to(float *x, float lower, float upper);

	typedef struct
	{
		char *content;
		uint32_t count, cap, type_size;
	} Lily_List;
	typedef Lily_List *Li_List;
	#define List_T(type) Li_List
	typedef struct
	{
		char *str;
		int32_t length;
	} Li_String_def;
	typedef Li_String_def *Li_String;

	Li_List str_split(char *str, char split_char);

	Li_List str_split_by_str(char *str, const char *split_char);

	Li_List str_find(char *s, const char *find);

	Li_List str_find_sort(char *s, const char *find);

#define list_index(list, i) (list->content + i * list->type_size)
// e.g.: Li_list list = new_li(int32_t);
#define new_li(type) new_list(sizeof(type), 4)
// e.g.: Li_list list = new_li_cap(int32_t,8);
#define new_li_cap(type, cap) new_list(sizeof(type), cap)
// e.g.: int32_t index = li_add(list,item);
#define li_add(list, obj) (list_add(list, &(obj)))
// e.g.: string* strs = list_content(list, string);
#define list_content(list, type) ((type *)(list->content))

	int32_t init_list(Lily_List *list, uint32_t unit_size2, uint32_t init_cap);
	Lily_List *new_list(uint32_t type, uint32_t init_cap);
	int32_t list_recap(Lily_List *list, uint32_t new_cap);
	int32_t list_add(Lily_List *list, void *c);
	int32_t list_remove_at(Lily_List *list, uint32_t index);
	int32_t list_swap_out(Lily_List *list, uint32_t index);
	int32_t list_item_equal(void *item1, void *item2, uint32_t type);
	int32_t list_remove(Lily_List *list, void *item);
	int32_t list_find(Lily_List *list, void *item);
	void *list_get(Lily_List *list, uint32_t index);
	int32_t delete_list(Lily_List *list);
	int32_t delete_list_recursively(Lily_List *list);

	int32_t list_reduction(Li_List list);

	int32_t list_insert(Li_List list, void *c, int32_t at);

	int list_sort(Lily_List *list, int (*compare)(const void *, const void *));
	
	int list_find_binary(Lily_List *list, void *item, int (*compare)(const void *, const void *));

	Li_String new_li_string_by(char *str);
	// use strdup() instead
	char *new_string_by(char *str);

	void delete_li_string(Li_String li);

	int32_t assign_li_string(Li_String li, char *source);

	int32_t str_wrap(char *s, char c);
	int32_t str_wrap_by_str(char *s, const char *cs);

	int32_t str_left_wrap(char *s, char c);

	char *dynamic_str_cat(char *str, const char *sub);

	int str_translate(char *_str);

	Li_List str_cmd_split(char *_str);

	Li_List str_count(char *str1, const char *str2);

#ifdef __cplusplus
}
#endif

#endif // !LILY_BASIC
